package com.ai.platform.spider.core.collocate;
import com.ai.platform.spider.utils.Properties;
import com.ai.platform.spider.utils.SpiderUtil;
import org.w3c.dom.*;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathFactory;
import java.util.ArrayList;
import java.util.List;

public class XMLConfBuilder extends DefaultConfBuilder {

    private XPath xpath;
    private Document doc;
    private Transformer transformer;

    public XMLConfBuilder(String file) {
        super();
        DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
        try {
            DocumentBuilder db = dbf.newDocumentBuilder();
            this.doc = db.parse(SpiderUtil.asStream(file));
            XPathFactory xf = XPathFactory.newInstance();
            this.xpath = xf.newXPath();
            this.transformer = TransformerFactory.newInstance().newTransformer();
        } catch (Throwable e) {
            e.printStackTrace();
            System.out.println("初始化XML解析失败");
        }
    }

    /**
     * @param doc
     * @param modelXpath
     * @return 匹配的节点
     */
    protected List<Node> extractModel(Object doc, String modelXpath) {
        NodeList nodeList = null;
        try {
            nodeList = (NodeList) xpath.compile(modelXpath).evaluate(doc, XPathConstants.NODESET);
        } catch (Throwable e) {
            e.printStackTrace();
        }
        if (nodeList == null || nodeList.getLength() == 0) {
            return null;
        }

        List<Node> mNodes = new ArrayList<>();
        for (int i = 0; i < nodeList.getLength(); i++) {
            Node node = nodeList.item(i);
            mNodes.add(node);
        }
        return mNodes;
    }


    @Override
    public void configParams(Properties params) {
        //写入属性值
        List<Node> list = extractModel(doc, "//property");
        if(null!=list && list.size()>0) {
            for (int i = 0; i < list.size(); i++) {
                NamedNodeMap nodeMap = list.get(i).getAttributes();
                params.put(nodeAttrValue(nodeMap,"key",""), nodeAttrValue(nodeMap,"value",""));
            }
        }
    }

    @Override
    public void configSeeds(Config.Seeds seeds) {
        //入口种子
        List<Node> list = extractModel(doc, "//seed");
        if(null!=list && list.size()>0) {
            for (int i = 0; i < list.size(); i++) {
                NamedNodeMap nodeMap = list.get(i).getAttributes();
                Seed seed=new Seed(nodeAttrValue(nodeMap,"name",""), nodeAttrValue(nodeMap,"url",""));
                seeds.add(seed);
            }
        }
    }

    @Override
    public void configRules(Config.Rules rules) {
        //规则
        List<Node> list = extractModel(doc, "//rule");
        if(null!=list && list.size()>0) {
            for (int i = 0; i < list.size(); i++) {
                NamedNodeMap nodeMap = list.get(i).getAttributes();
                Rule rule=new Rule(nodeAttrValue(nodeMap,"key",""), nodeAttrValue(nodeMap,"class",""));
                rules.add(rule);
            }
        }
    }

    @Override
    public void configDocs(Config.Docs docs) {
        //匹配文档
        List<Node> docList = extractModel(doc, "//doc");
        if(null!=docList && docList.size()>0) {
            for (int i = 0; i < docList.size(); i++) {
                //取得doc属性
                NamedNodeMap nodeMap = docList.get(i).getAttributes();
                Doc doc=new Doc(nodeAttrValue(nodeMap,"name",""),nodeAttrValue(nodeMap,"ruleKey",""));
                NodeList childNodes=docList.get(i).getChildNodes();
                if(null!=childNodes && childNodes.getLength()>0){
                    List<Field> fieldList=new ArrayList<>();
                    for (int j=0;j<childNodes.getLength();j++) {
                        Node childNode = childNodes.item(j);
                        NamedNodeMap childNodeMap = childNode.getAttributes();
                        if("url-match-rule".equals(childNode.getNodeName())) {
                            //url-match-rule
                            String type=nodeAttrValue(childNodeMap,"type","");
                            String value=nodeAttrValue(childNodeMap,"value","");
                            UrlMatchRule urlMatchRule=new UrlMatchRule(type,value);
                            doc.setUrlMatchRule(urlMatchRule);
                        }else if("field".equals(childNode.getNodeName())){
                            //field
                            Field field=new Field();
                            field.setName(nodeAttrValue(childNodeMap,"name",""));
                            field.setValue(nodeAttrValue(childNodeMap,"value",""));
                            field.setAttr(nodeAttrValue(childNodeMap,"attr",""));
                            field.setXpath(nodeAttrValue(childNodeMap,"xpath",""));
                            field.setArray("1".equals(nodeAttrValue(childNodeMap,"isArray","0")));
                            if(field.isArray()){
                                List<Field>  childFieldList=new ArrayList<>();
                                NodeList nodeList2=childNode.getChildNodes();
                                if(null!=nodeList2 && nodeList2.getLength()>0){
                                    for(int k=0;k<nodeList2.getLength();k++){
                                        Node node2=nodeList2.item(k);
                                        if("field".equals(node2.getNodeName())) {
                                            NamedNodeMap childNodeMap2 = node2.getAttributes();
                                            Field childField = new Field();
                                            childField.setName(nodeAttrValue(childNodeMap2,"name",""));
                                            childField.setValue(nodeAttrValue(childNodeMap2,"value",""));
                                            childField.setAttr(nodeAttrValue(childNodeMap2,"attr",""));
                                            childField.setXpath(nodeAttrValue(childNodeMap2,"xpath",""));
                                            childFieldList.add(childField);
                                        }
                                    }
                                }
                                field.setFieldList(childFieldList);
                            }
                            fieldList.add(field);
                        }
                    }
                    doc.setFieldList(fieldList);
                }
                docs.add(doc);
            }
        }
    }

    private String nodeAttrValue(NamedNodeMap nodeMap,String key,String defaults){
        Node node=nodeMap.getNamedItem(key);
        if(null==node){
            return defaults;
        }
        return node.getNodeValue();
    }

}
